import { Button, Component, find } from 'cc'
import { ZBaseBinder } from './ZBaseBinder'

/**
 * 点击事件绑定选项接口
 */
export interface ClickBindingOptions {
	/** 是否静默处理错误 */
	silent?: boolean
	/** 是否为可选绑定（不存在时不报错） */
	optional?: boolean
	/** 如果Button组件不存在，是否创建 */
	createButton?: boolean
	/** 自定义错误处理函数 */
	onError?: (error: string) => void
}

/**
 * 批量点击事件绑定配置类型
 */
export type ClickBindingConfig =
	| string
	| {
			path: string
			method?: string
			silent?: boolean
			optional?: boolean
			createButton?: boolean
			onError?: (error: string) => void
	  }

/**
 * 点击绑定器
 *
 * 负责将节点的点击事件绑定到组件方法，支持单个绑定和批量绑定。
 * 可以绑定已有Button组件的节点，或者自动创建Button组件。
 *
 * @example
 * // 创建绑定器
 * const binder = new ZClickBinder(this);
 *
 * // 绑定点击事件
 * binder.bindClick('UI/StartButton', 'onStartButtonClick');
 *
 * // 带选项的绑定
 * binder.bindClick('UI/SettingsButton', 'onSettingsButtonClick', {
 *   optional: true,
 *   createButton: true
 * });
 *
 * // 批量绑定
 * binder.bindClicks({
 *   onStartButtonClick: 'UI/StartButton',
 *   onSettingsButtonClick: {
 *     path: 'UI/SettingsButton',
 *     optional: true
 *   }
 * });
 */
export class ZClickBinder extends ZBaseBinder {
	/**
	 * 创建点击绑定器
	 * @param component 要绑定事件的组件实例
	 */
	constructor(component: Component) {
		super(component)
	}

	/**
	 * 绑定节点的点击事件到组件方法
	 * @param path 节点路径，相对于组件所在节点
	 * @param method 要绑定的方法名
	 * @param options 绑定选项
	 * @returns this 实例，支持链式调用
	 */
	public bindClick(path: string, method: string, options: ClickBindingOptions = {}): this {
		const {
			silent = false,
			optional = false,
			createButton = false, // 默认不自动创建Button组件
			onError
		} = options

		// 检查方法是否存在
		if (typeof this.component[method] !== 'function') {
			this.handleError(`Method "${method}" not found in ${this.component.constructor.name}`, silent, onError)
			return this
		}

		// 查找节点
		const node = find(path, this.component.node)
		if (!node) {
			if (!optional) {
				this.handleError(
					`Node not found at path: "${path}" in ${this.component.constructor.name}`,
					silent,
					onError
				)
			}
			return this
		}

		// 检查Button组件
		let button = node.getComponent(Button)
		if (!button) {
			if (createButton) {
				// 仅当明确指定时才创建Button组件
				button = node.addComponent(Button)
			} else {
				this.handleError(
					`Button component not found on node at path: "${path}". Set createButton=true to auto-create.`,
					silent,
					onError
				)
				return this
			}
		}

		// 绑定点击事件
		node.on(Button.EventType.CLICK, () => {
			// 调用目标方法
			this.component[method].call(this.component)
		})

		return this
	}

	/**
	 * 批量绑定点击事件
	 * @param bindings 绑定配置对象 { 方法名: 配置 } 或 { 自定义键: { path: 路径, method: 方法名, ... } }
	 * @returns this 实例，支持链式调用
	 */
	public bindClicks(bindings: Record<string, ClickBindingConfig>): this {
		const keys = Object.keys(bindings)
		for (let i = 0; i < keys.length; i++) {
			const key = keys[i]
			const config = bindings[key]

			if (typeof config === 'string') {
				// 简单字符串路径，使用键作为方法名
				this.bindClick(config, key)
			} else {
				// 带选项的对象
				const path = config.path
				const method = config.method || key
				const options = {
					silent: config.silent,
					optional: config.optional,
					createButton: config.createButton,
					onError: config.onError
				}
				this.bindClick(path, method, options)
			}
		}
		return this
	}

	/**
	 * 处理错误
	 * @param message 错误消息
	 * @param silent 是否静默处理
	 * @param onError 自定义错误处理函数
	 * @private
	 */
	private handleError(message: string, silent: boolean, onError?: (error: string) => void): void {
		if (onError) {
			// 使用自定义错误处理
			onError(message)
		} else if (!silent) {
			// 默认错误处理
			console.error(`[ZClickBinder] ${message}`)
		}
	}
}
